using System;
using System.Drawing;
using System.IO;
using System.Security.Cryptography;
using System.Windows.Forms;
using OpenComposite.Forms;
using System.Globalization;

namespace OpenComposite.Base
{
	/// <summary>
	/// Static Helper Class.
	/// </summary>
	public static class Helper
	{
		#region Static Properties
		public static Guid InboxApplicationId
		{
			get { return new Guid("{E23A4330-8843-4CB7-AE45-3221A1942FA5}"); }
		}
		public static Guid DesignerApplicationId
		{
			get { return new Guid("{5C0DCF49-98A3-4F82-95A3-B5E4D26B6908}"); }
		}
		/// <summary>
		/// Gets the exact date time format (including milli seconds).
		/// </summary>
		/// <value>The exact date time format.</value>
		public static string ExactDateTimeFormat
		{
			get
			{
				return string.Format("{0} {1}.ffff",
				 CultureInfo.CurrentUICulture.DateTimeFormat.ShortDatePattern,
				 CultureInfo.CurrentUICulture.DateTimeFormat.LongTimePattern);
			}
		}
		#endregion

		#region Static Methods

		/// <summary>
		/// Checks of the catched Exception was an BaseException 
		/// if yes the Exception will be forwarded
		/// if no a new BaseException will be forwarded
		/// </summary>
		/// <param name="catchedEx"></param>
		/// <param name="newEx"></param>
		/// <returns>BaseException</returns>
		public static BaseException ReturnEx(Exception catchedEx, BaseException newEx)
		{
			BaseException aEx = catchedEx as BaseException;
			if ( aEx == null )
				return newEx;
			else
				return aEx;
		}

		/// <summary>
		/// Show an exception.
		/// </summary>
		/// <param name="exception"></param>
		public static void ShowException(Exception exception)
		{
			string msg = "";
			Exception inner = exception;
			while ( inner != null ) {
				msg += inner.Message + Environment.NewLine;
				inner = inner.InnerException;
			}
			//MessageBox.Show(msg, ProductName, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
			ErrorBox.Show(exception);
		}

		/// <summary>
		/// Show an exception.
		/// </summary>
		/// <param name="message">A message string.</param>
		/// <param name="exception">An exception object.</param>
		public static void ShowException(string message, Exception exception)
		{
			string msg = message + Environment.NewLine;
			Exception inner = exception;
			while ( inner != null ) {
				msg += inner.Message + Environment.NewLine;
				inner = inner.InnerException;
			}
			//MessageBox.Show(msg, ProductName, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
			ErrorBox.Show(exception, message);
		}

		/// <summary>
		/// Ask user.
		/// </summary>
		/// <param name="message">Message.</param>
		/// <returns>A DialogResult.</returns>
		public static DialogResult AskYesNo(string message)
		{
			return MessageBox.Show(message, Application.ProductName, MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2);
		}

		/// <summary>
		/// Ask user showing a warning.
		/// </summary>
		/// <param name="message">Message.</param>
		/// <returns>A DialogResult.</returns>
		public static DialogResult AskYesNoWarning(string message)
		{
			return MessageBox.Show(message, Application.ProductName, MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2);
		}

		/// <summary>
		/// Show info message.
		/// </summary>
		/// <param name="message">The message string.</param>
		/// <param name="parameter">Parameter array.</param>
		public static void ShowInfo(string message)
		{
			MessageBox.Show(message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Information);
		}

		/// <summary>
		/// Show info message.
		/// </summary>
		/// <param name="message">The message string.</param>
		/// <param name="parameter">Parameter array.</param>
		public static void ShowInfo(string message, params object[] parameter)
		{
			MessageBox.Show(string.Format(message, parameter), Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Information);
		}

		/// <summary>
		/// Show warning message.
		/// </summary>
		/// <param name="message">The message string.</param>
		public static void ShowWarning(string message)
		{
			MessageBox.Show(message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
		}

		/// <summary>
		/// Show warning message.
		/// </summary>
		/// <param name="message">The message string.</param>
		/// <param name="parameter">Parameter array.</param>
		public static void ShowWarning(string message, params object[] parameter)
		{
			string msg = string.Format(message, parameter);
			MessageBox.Show(msg, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
		}

		/// <summary>
		/// Gets the hashed string using SHA512.
		/// </summary>
		/// <param name="text">The string to hash.</param>
		/// <returns>The hash as a base64 string.</returns>
		public static string GetHashedString(string text)
		{
			try {
				SHA512 hash = new SHA512Managed();
				//hash.ComputeHash(
				byte[] writeBuffer;
				using ( MemoryStream ms = new MemoryStream() )
				using ( StreamWriter sw = new StreamWriter(ms) ) {
					sw.Write(text);
					sw.Flush();
					ms.Position = 0;
					writeBuffer = hash.ComputeHash(ms);
				}
				string hashed = Convert.ToBase64String(writeBuffer);
				return hashed;
			} catch ( Exception ) {
				MessageBox.Show("Error while generating hash code");
				return string.Empty;
			}
		}

		/// <summary>
		/// [NOT USED!] Gets the MD5 hash of a string as a base64 string.
		/// </summary>
		/// <param name="text">The text to hash.</param>
		/// <returns>The base64 string value of the hash.</returns>
		public static string GetMD5Hash(string text)
		{
			try {
				MD5 hash = MD5.Create();
				byte[] writeBuffer;
				using ( MemoryStream ms = new MemoryStream() )
				using ( StreamWriter sw = new StreamWriter(ms) ) {
					sw.Write(text);
					sw.Flush();
					ms.Position = 0;
					writeBuffer = hash.ComputeHash(ms);
				}
				string hashed = Convert.ToBase64String(writeBuffer);
				return hashed;
			} catch ( Exception ) {
				MessageBox.Show("Error while generating hash code");
				return string.Empty;
			}
		}
		/// <summary>
		/// Gets the MD5 hash of a string as a hexadecimal value string. Used for integrity and currency checks (rules).
		/// </summary>
		/// <param name="text">The text to hash.</param>
		/// <returns>
		/// The hexadecimal string value of the hash.
		/// </returns>
		public static string GetMD5HashAsHex(string text)
		{
			try {
				MD5 hash = MD5.Create();
				byte[] writeBuffer;
				using ( MemoryStream ms = new MemoryStream() )
				using ( StreamWriter sw = new StreamWriter(ms) ) {
					sw.Write(text);
					sw.Flush();
					ms.Position = 0;
					writeBuffer = hash.ComputeHash(ms);
				}
				string hashed = BitConverter.ToString(writeBuffer).Replace("-", "");
				return hashed;
			} catch ( Exception ) {
				MessageBox.Show("Error while generating hash code");
				return string.Empty;
			}
		}

		public static string ConvertBytesToHexString(byte[] value)
		{
			return BitConverter.ToString(value).Replace("-", "");
		}
		public static byte[] ConvertHexStringToBytes(string value)
		{
			int arrayLength = value.Length / 2;
			byte[] bytes = new byte[arrayLength];
			for ( int i = 0, j = 0; i < value.Length; i = i + 2, j++ ) {
				string strHex;
				strHex = value.Substring(i, 2);
				bytes[j] = Convert.ToByte(strHex, 16);
			}
			return bytes;
		}

		/// <summary>
		/// Creates a drag'n'drop cursor from a tree node.
		/// </summary>
		/// <param name="contextControl">The context control.</param>
		/// <param name="effect">The effect.</param>
		/// <param name="node">The tree node.</param>
		/// <returns>A <see cref="T:OpenComposite.Base.BitmapCursor"/>.</returns>
		public static BitmapCursor CreateDragCursorFromTreeNode(
			Control contextControl, DragDropEffects effect, TreeNode node)
		{
			Cursor cursor;
			switch ( effect ) {
				case DragDropEffects.None: cursor = Cursors.No; break;
				default: cursor = Cursors.Default; break;
			}
			int width = node.Bounds.Width;
			int height = node.Bounds.Height;
			if ( node.TreeView != null && node.TreeView.ImageList != null ) {
				width += node.TreeView.ImageList.ImageSize.Width;
			}
			Rectangle r = new Rectangle(0, 0, width + 1, height + 1);

			using ( Bitmap bmp = new Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format32bppArgb) )
			using ( Graphics g = Graphics.FromImage(bmp) ) {
				System.Drawing.Text.TextRenderingHint originalTextRenderingHint = g.TextRenderingHint;
				g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SingleBitPerPixelGridFit;
				g.Clear(Color.FromArgb(0, 255, 255, 255));

				Color cb1 = Color.FromArgb(32, 255, 255, 255);
				Color cb2 = Color.FromArgb(0, 255, 255, 255);
				using ( Brush b = new System.Drawing.Drawing2D.LinearGradientBrush(r, cb1, cb2, 0, false) )
					g.FillRectangle(b, 0, 0, width, height);

				float textxpos = 0.0f;
				if ( node.TreeView != null && node.TreeView.ImageList != null ) {
					if ( node.ImageIndex >= 0 ) {
						g.DrawImage(node.TreeView.ImageList.Images[node.ImageIndex], 0, 0);
						textxpos = node.TreeView.ImageList.ImageSize.Width;
					} else if ( !string.IsNullOrEmpty(node.ImageKey) ) {
						g.DrawImage(node.TreeView.ImageList.Images[node.ImageKey], 0, 0);
						textxpos = node.TreeView.ImageList.ImageSize.Width;
					} else {
						g.DrawImage(node.TreeView.ImageList.Images[0], 0, 0);
						textxpos = node.TreeView.ImageList.ImageSize.Width;
					}
				}

				Color ct1 = Color.FromArgb(196, SystemColors.ControlText);
				using ( Brush b = new System.Drawing.SolidBrush(ct1) ) {
					g.DrawString(node.Text, contextControl.Font, b, textxpos, 0);
				}
				g.TextRenderingHint = originalTextRenderingHint;
				return new BitmapCursor(cursor, bmp, effect);
			}
		}
		/// <summary>
		/// Creates a drag'n'drop cursor.
		/// </summary>
		/// <param name="image">The image.</param>
		/// <param name="text">The text.</param>
		/// <param name="font">The font.</param>
		/// <param name="effect">The drag'n'drop effect.</param>
		/// <returns>A <see cref="T:OpenComposite.Base.BitmapCursor"/>.</returns>
		public static BitmapCursor CreateDragCursor(
			Image image, string text, Font font, DragDropEffects effect)
		{
			// select base cursor
			Cursor cursor;
			switch ( effect ) {
				case DragDropEffects.None: cursor = Cursors.No; break;
				default: cursor = Cursors.Default; break;
			}
			int width = 1;
			int height = 1;
			// create helper bitmap and graphics for string measuring
			using ( Bitmap bmp = new Bitmap(1, 1, System.Drawing.Imaging.PixelFormat.Format32bppArgb) )
			using ( Graphics g = Graphics.FromImage(bmp) ) {
				// disable text antialiasing
				System.Drawing.Text.TextRenderingHint originalTextRenderingHint = g.TextRenderingHint;
				g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SingleBitPerPixelGridFit;
				// calculate info image size (image + text)
				SizeF sizef = g.MeasureString(text, font);
				width = (int)Math.Ceiling(sizef.Width) + 1;
				height = (int)Math.Ceiling(sizef.Height) + 1;
				if ( image != null ) {
					width += image.Width + 1;
					if ( height < image.Height ) height = image.Height;
				}
				g.TextRenderingHint = originalTextRenderingHint;
			}
			// create bitmap and graphics
			using ( Bitmap bmp = new Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format32bppArgb) )
			using ( Graphics g = Graphics.FromImage(bmp) ) {
				// disable text antialiasing
				System.Drawing.Text.TextRenderingHint originalTextRenderingHint = g.TextRenderingHint;
				g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SingleBitPerPixelGridFit;
				// clear graphic
				g.Clear(Color.FromArgb(0, 255, 255, 255));
				Rectangle rect = new Rectangle(0, 0, width, height);
				// fill text background with a linear gradient
				Color cb1 = Color.FromArgb(32, 255, 255, 255);
				Color cb2 = Color.FromArgb(0, 255, 255, 255);
				using ( Brush b = new System.Drawing.Drawing2D.LinearGradientBrush(rect, cb1, cb2, 0, false) ) {
					g.FillRectangle(b, 0, 0, width, height);
				}
				// text x position
				float textxpos = 0.0f;
				// draw image
				if ( image != null ) {
					g.DrawImage(image, 0, 0);
					textxpos = image.Width + 1;
				}
				// draw text
				Color ct1 = Color.FromArgb(196, SystemColors.ControlText);
				using ( Brush b = new System.Drawing.SolidBrush(ct1) ) {
					g.DrawString(text, font, b, textxpos, 0);
				}
				g.TextRenderingHint = originalTextRenderingHint;
				// create BitmapCursor
				return new BitmapCursor(cursor, bmp, effect);
			}
		}
		/// <summary>
		/// Creates a drag'n'drop cursor.
		/// </summary>
		/// <param name="cursor">The cursor.</param>
		/// <param name="image">The drag item image.</param>
		/// <param name="text">The drag item text.</param>
		/// <param name="font">The drag item text font.</param>
		/// <returns>A <see cref="T:OpenComposite.Base.BitmapCursor"/>.</returns>
		public static BitmapCursor CreateDragCursor(
			Cursor cursor, Image image, string text, Font font)
		{
			int width = 1;
			int height = 1;
			// create helper bitmap and graphics for string measuring
			using ( Bitmap bmp = new Bitmap(1, 1, System.Drawing.Imaging.PixelFormat.Format32bppArgb) )
			using ( Graphics g = Graphics.FromImage(bmp) ) {
				// disable text antialiasing
				System.Drawing.Text.TextRenderingHint originalTextRenderingHint = g.TextRenderingHint;
				g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SingleBitPerPixelGridFit;
				// calculate info image size (image + text)
				SizeF sizef = g.MeasureString(text, font);
				width = (int)Math.Ceiling(sizef.Width) + 1;
				height = (int)Math.Ceiling(sizef.Height) + 1;
				if ( image != null ) {
					width += image.Width + 1;
					if ( height < image.Height ) height = image.Height;
				}
				g.TextRenderingHint = originalTextRenderingHint;
			}
			// create bitmap and graphics
			using ( Bitmap bmp = new Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format32bppArgb) )
			using ( Graphics g = Graphics.FromImage(bmp) ) {
				// disable text antialiasing
				System.Drawing.Text.TextRenderingHint originalTextRenderingHint = g.TextRenderingHint;
				g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SingleBitPerPixelGridFit;
				// clear graphic
				g.Clear(Color.FromArgb(0, 255, 255, 255));
				Rectangle rect = new Rectangle(0, 0, width, height);
				// fill text background with a linear gradient
				Color cb1 = Color.FromArgb(32, 255, 255, 255);
				Color cb2 = Color.FromArgb(0, 255, 255, 255);
				using ( Brush b = new System.Drawing.Drawing2D.LinearGradientBrush(rect, cb1, cb2, 0, false) ) {
					g.FillRectangle(b, 0, 0, width, height);
				}
				// text x position
				float textxpos = 0.0f;
				// draw image
				if ( image != null ) {
					g.DrawImage(image, 0, 0);
					textxpos = image.Width + 1;
				}
				// draw text
				Color ct1 = Color.FromArgb(196, SystemColors.ControlText);
				using ( Brush b = new System.Drawing.SolidBrush(ct1) ) {
					g.DrawString(text, font, b, textxpos, 0);
				}
				g.TextRenderingHint = originalTextRenderingHint;
				// create BitmapCursor
				return new BitmapCursor(cursor, bmp);
			}
		}
		#endregion Static Methods
	}

	/// <summary>
	/// WaitMouse class.
	/// usage:
	/// 
	/// using(new WaitMouse())
	/// {
	///    your code
	/// }
	/// </summary>
	public class WaitMouse : IDisposable
	{
		#region Members

		#region Private Vars

		/// <summary>
		/// Keep the old cursor.
		/// </summary>
		private Cursor m_OldCursor;

		#endregion Private Vars

		#endregion Members

		#region Contstructors

		/// <summary>
		/// Create WaitMouse instance.
		/// </summary>
		public WaitMouse()
		{
			//Application.DoEvents();
			m_OldCursor = Cursor.Current;
			Cursor.Current = Cursors.WaitCursor;
			//Application.DoEvents();
		}


		#endregion Constructors

		#region Systemstuff

		/// <summary>
		/// Clean up any resources being used.
		/// </summary>
		public void Dispose()
		{
			try {
				Cursor.Current = m_OldCursor;
			} catch { }
		}

		#endregion Systemstuff

	}
}
